package com.ushine.web.component.submit;


import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.ushine.web.component.exception.ServiceException;
import com.ushine.web.component.exception.ServiceExceptionEnum;
import com.ushine.web.security.utils.SecurityUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.context.annotation.Configuration;

import java.io.File;
import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;

/**
 * @Author: yls
 * @Date 2022/3/25 20:04
 * @Description: 自定义切面拦截
 * @Version 1.0
 **/
@Slf4j
@Aspect
@Configuration
public class LockMethodInterceptor {
    /**
     * 锁对象
     */
    private static final Object LOCAL_REQUEST_LOCK = new Object();

    /**
     * 本地缓存对象
     */
    private static final Cache<String, Integer> CACHES = CacheBuilder.newBuilder()
            // 最大缓存10000个
            .maximumSize(10000)
            // 设置写缓存后10秒钟过期
            .expireAfterAccess(10, TimeUnit.SECONDS)
            .build();


    @Around("@annotation(com.ushine.web.component.submit.LocalLockRequest)")
    public Object interceptor(ProceedingJoinPoint pjq) throws Throwable {
        MethodSignature signature = (MethodSignature) pjq.getSignature();
        Method method = signature.getMethod();
        LocalLockRequest localLockRequest = method.getAnnotation(LocalLockRequest.class);
        String key = getKey(localLockRequest.key());
        if (!StringUtils.isEmpty(key)) {
            // 根据key加锁，避免多线程通过
            synchronized (LOCAL_REQUEST_LOCK) {
                if (CACHES.getIfPresent(key) == null) {
                    // 如果是第一次请求
                    CACHES.put(key, 1);
                } else {
                    throw new ServiceException(ServiceExceptionEnum.REPEAT_SUBMISSION);
                }
            }
        }
        return pjq.proceed();
    }


    /**
     * 功能描述:
     * 〈 生成key 〉
     *
     * @param key 主键
     * @return : java.lang.String
     * @author : yls
     * @date : 2022/3/25 20:16
     */
    private String getKey(String key) {
        String username = SecurityUtils.getUsername();
        return username + File.separator + key;
    }
}
